/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: Dec 31, 2009
 * Time: 10:30:32 AM
 * To change this template use File | Settings | File Templates.
 */
import java.util.*;
import org.jdom.*;

// Referenced classes of package dk.brics.dsd:
//            Rule, InternalSchemaErrorException, SchemaErrorException, Context,
//            Definition, Validator, Boolexp

public class Schema extends Rule
{

    static boolean isDSDElement(Object obj)
    {
        if(!(obj instanceof Element))
            return false;
        Element element = (Element)obj;
        String s = element.getNamespaceURI();
        if(s.equals("http://www.w3.org/2001/XInclude"))
            throw new RuntimeException("non-expanded XInclude in schema");
        else
            return s.equals("http://www.brics.dk/DSD/2.0");
    }

    public Schema(Document document)
        throws SchemaErrorException
    {
        try
        {
            fill(document.getRootElement(), null);
        }
        catch(InternalSchemaErrorException internalschemaerrorexception)
        {
            throw new SchemaErrorException();
        }
    }

    Schema(Element element, Schema schema)
    {
        fill(element, schema);
    }

    void fill(Element element, Schema schema)
    {
        if(!isDSDElement(element))
            throw new InternalSchemaErrorException();
        enclosing = schema;
        if(schema == null)
        {
            definitions = new Hashtable();
            rules = new ArrayList();
            outermost = this;
            boolexpcount = '\uE000';
        } else
        {
            definitions = schema.definitions;
            rules = schema.rules;
            outermost = schema.outermost;
        }
        root = element.getAttributeValue("root");
        if(root != null)
        {
            root_local = pnameLocal(root);
            root_uri = penameURI(root, element);
        }
        Iterator iterator = element.getChildren().iterator();
        do
        {
            if(!iterator.hasNext())
                break;
            Element element1 = (Element)iterator.next();
            if(isDSDElement(element1))
            {
                String s = element1.getName();
                if((s.equals("rule") || s.equals("stringtype") || s.equals("contenttype") || s.equals("boolexp")) && element1.getAttributeValue("id") != null)
                {
                    Definition definition = Definition.parse(element1, this);
                    definitions.put(definition.id, definition);
                } else
                if(s.equals("declare") || s.equals("require") || s.equals("if") || s.equals("unique") || s.equals("pointer") || s.equals("rule"))
                    rules.add(Rule.parse(element1, this));
                else
                if(s.equals("dsd"))
                    Rule.parse(element1, this);
            }
        } while(true);
    }

    void checkRoots(Set set)
    {
        for(Iterator iterator = set.iterator(); iterator.hasNext(); checkRoot((Context)iterator.next()));
    }

    void checkRoot(Context context)
    {
        if(root == null)
            return;
        if(!matchPEname(root_local, root_uri, context.e.getName(), context.e.getNamespaceURI()))
            context.v.invalid(context, "invalid root element name " + Validator.getElementName(context.e), null);
    }

    char allocCodePoint(Boolexp boolexp)
    {
        if(outermost.boolexpcount == '\uF900')
            throw new InternalSchemaErrorException("too many BOOLEXP in REGEXP");
        else
            return outermost.boolexpcount++;
    }

    SortedSet findApplicableRules(Context context)
    {
        TreeSet treeset = new TreeSet();
        for(Iterator iterator = rules.iterator(); iterator.hasNext(); ((Rule)iterator.next()).findApplicableRules(context, treeset, new HashSet()));
        return treeset;
    }

    static String pnameLocal(String s)
    {
        int i = s.indexOf(58);
        if(i == -1)
            return s;
        else
            return s.substring(i + 1);
    }

    static String pnamePrefix(String s)
    {
        int i = s.indexOf(58);
        if(i == -1)
            return "";
        else
            return s.substring(0, i);
    }

    static boolean prefixDeclared(String s, Element element)
    {
        String s1 = pnamePrefix(s);
        if(s1.equals("xml") || s1.equals(""))
            return true;
        else
            return element.getNamespace(s1) != null;
    }

    static String penameURI(String s, Element element)
    {
        String s1 = pnamePrefix(s);
        if(s1.equals("xml"))
            return "http://www.w3.org/XML/1998/namespace";
        Namespace namespace = element.getNamespace(s1);
        if(namespace == null)
        {
            if(s1.equals(""))
                return "";
            else
                throw new InternalSchemaErrorException(s);
        } else
        {
            return namespace.getURI();
        }
    }

    static String panameURI(String s, Element element)
    {
        if(s.indexOf(58) == -1)
            return null;
        else
            return penameURI(s, element);
    }

    static boolean matchPEname(String s, String s1, String s2, String s3)
    {
        if(!s.equals("") && !s.equals(s2))
            return false;
        else
            return s1.equals(s3);
    }

    static boolean matchPAname(String s, String s1, String s2, String s3)
    {
        if(!s.equals("") && !s.equals(s2))
            return false;
        if(s3 == null || s1 == null)
            return s3 == null && s1 == null;
        else
            return s1.equals(s3);
    }

    static String replacePrefix(String s, Element element)
    {
        String s1 = penameURI(s, element);
        String s2 = pnameLocal(s);
        return s1 + ":" + s2;
    }

    static Element addPname(Element element, String s, String s1)
    {
        int i = s.indexOf(58);
        if(i == -1)
            return element.setAttribute("name", s);
        String s2 = s.substring(0, i);
        String s3 = s.substring(i + 1);
        boolean flag = false;
        while(!flag)
        {
            Namespace namespace = element.getNamespace(s2);
            if(namespace != null && !namespace.getURI().equals(s1))
                s2 = s2 + "x";
            else
                flag = true;
        }
        element.addNamespaceDeclaration(Namespace.getNamespace(s2, s1));
        return element.setAttribute("name", s2 + ":" + s3);
    }

    Schema enclosing;
    Schema outermost;
    String root;
    String root_local;
    String root_uri;
    Hashtable definitions;
    List rules;
    int rulecount;
    char boolexpcount;
    static final char first_reserved_cp = 57344;
    static final char last_reserved_cp = 63743;
}
